package io.itit.ecp.admin.server.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import icu.mhb.mybatisplus.plugln.base.service.impl.JoinServiceImpl;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.common.enums.IMeterDeviceEnums;
import io.itit.ecp.admin.server.entity.EnergyDataEntity;
import io.itit.ecp.admin.server.entity.MeterDeviceEntity;
import io.itit.ecp.admin.server.entity.extend.EnergyDataExtEntity;
import io.itit.ecp.admin.server.mapper.EnergyDataMapper;
import io.itit.ecp.admin.server.service.IEnergyDataService;
import io.itit.grass.common.server.dto.ParamDto;
import io.itit.grass.common.utils.Y666Utils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * <p>
 *
 * @Author：Roy
 * @Description：能源数据服务实现类
 * @Date：Create by 2023-12-05 11:48:22
 */
@Service
public class EnergyDataServiceImpl extends JoinServiceImpl<EnergyDataMapper, EnergyDataEntity> implements IEnergyDataService {

    @Override
    public EnergyDataExtEntity sum(ParamDto dto) {
        return Optional.ofNullable(baseMapper.sum(dto)).orElse(new EnergyDataExtEntity());
    }

    @Override
    public EnergyDataExtEntity sumMeterValue(ParamDto dto) {
        return baseMapper.sumMeterValue(dto);
    }

    @Override
    public EnergyDataExtEntity sumCarbonEmission(ParamDto dto) {
        return baseMapper.sumCarbonEmission(dto);
    }

    @Override
    public List<EnergyDataExtEntity> sumGroupEnergyType(ParamDto dto) {
        return baseMapper.sumGroupEnergyType(dto);
    }

    @Override
    public List<EnergyDataExtEntity> sumGroupEnergyTypeAndScene(ParamDto dto) {
        return baseMapper.sumGroupEnergyTypeAndScene(dto);
    }

    @Override
    public List<EnergyDataExtEntity> sumGroupReadMeterTypeAndScene(ParamDto dto) {
        return baseMapper.sumGroupReadMeterTypeAndScene(dto);
    }

    @Override
    public List<EnergyDataExtEntity> sumGroupScene(ParamDto dto) {
        return this.baseMapper.sumGroupScene(dto);
    }

    @Override
    public List<EnergyDataExtEntity> sumGroupSolidifyDate(ParamDto dto) {
        return baseMapper.sumGroupSolidifyDate(dto);
    }

    @Override
    public List<EnergyDataExtEntity> sumGroupSolidifyDateAndEnergyType(ParamDto dto) {
        return baseMapper.sumGroupSolidifyDateAndEnergyType(dto);
    }

    @Override
    public List<EnergyDataExtEntity> sumGroupSolidifyDateAndReadMeterType(ParamDto dto) {
        return baseMapper.sumGroupSolidifyDateAndReadMeterType(dto);
    }

    @Override
    public List<EnergyDataExtEntity> sumGroupReadMeterType(ParamDto dto) {
        return baseMapper.sumGroupReadMeterType(dto);
    }

    @Override
    public IPage<EnergyDataExtEntity> deviceMeterStatistics(ParamDto dto, Page<EnergyDataExtEntity> page) {
        return this.baseMapper.deviceMeterStatistics(dto, page);
    }

    @Override
    public List<EnergyDataExtEntity> deviceMeterExport(ParamDto dto) {
        return this.baseMapper.deviceMeterStatistics(dto);
    }


    @Override
    public IPage<EnergyDataExtEntity> companyMeterStatistics(ParamDto dto, Page<EnergyDataExtEntity> page) {
        return this.baseMapper.companyMeterStatistics(dto, page);
    }

    @Override
    public List<EnergyDataExtEntity> companyMeterExport(ParamDto dto) {
        return this.baseMapper.companyMeterStatistics(dto);
    }

    @Override
    public IPage<EnergyDataExtEntity> projectMeterStatistics(ParamDto dto, Page<EnergyDataExtEntity> page) {
        return this.baseMapper.projectMeterStatistics(dto, page);
    }

    @Override
    public List<EnergyDataExtEntity> projecMeterExport(ParamDto dto) {
        return this.baseMapper.projectMeterStatistics(dto);

    }

    @Override
    @Transactional
    public void updateByEnergyTypeId(String energyTypeId, String rangeId, String energyCategory, String energyUnit) {
        this.lambdaUpdate()
                .set(EnergyDataEntity::getCalculationRange, rangeId)
                .set(EnergyDataEntity::getEnergyTypeUnit, energyUnit)
                .set(EnergyDataEntity::getEnergyCategory, energyCategory)
                .set(EnergyDataEntity::getEnergyTypeId, energyTypeId)
                .update();
    }

    @Override
    @Transactional
    public boolean causeFactorUpdate(boolean isCarbonEmission, String energyTypeId, Date solidifyDate, BigDecimal factor) {
        List<EnergyDataEntity> energyDataEntities = Joins.of(EnergyDataEntity.class)
                .selectAll()
                .leftJoin(MeterDeviceEntity.class, MeterDeviceEntity::getId, EnergyDataEntity::getMeterDeviceId)
                .selectAs(t -> t.addFunAlias(MeterDeviceEntity::getReadMeterType, EnergyDataExtEntity::getReadMeterType))
                .notIn(isCarbonEmission, MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .in(!isCarbonEmission, MeterDeviceEntity::getReadMeterType, IMeterDeviceEnums.ReadMeterType.getZeroCarbonList())
                .end()
                .eq(EnergyDataEntity::getEnergyTypeId, energyTypeId)
                .ge(EnergyDataEntity::getSolidifyDate, DateUtil.beginOfMonth(solidifyDate))
                .le(EnergyDataEntity::getSolidifyDate, DateUtil.endOfMonth(solidifyDate))
                .joinList(EnergyDataEntity.class);
        if (CollectionUtils.isNotEmpty(energyDataEntities)) {
            // 重新计算碳排/碳减数据的值
            energyDataEntities.forEach(entity -> calc(factor, entity));
            return updateBatchById(energyDataEntities);
        }
        return true;
    }

    private void calc(BigDecimal factor, EnergyDataEntity dataEntity) {
        BigDecimal multiply = Y666Utils.multiply(dataEntity.getMeterValue(), factor);
        dataEntity.setCarbonEmission(multiply);
        dataEntity.setCarbonEmissionProcess(dataEntity.getMeterValue() + "*" + factor);
    }
}
